<template>
  <div class="list">
    <div class="list-item" draggable="true" style="--color: #e63e31">
      <svg-icon icon-class="iconfont-shuangyuzuo" class="constellation"></svg-icon>
      <span class="list-item-title">双鱼座</span>
    </div>
    <div class="list-item" draggable="true" style="--color: #70d265">
      <svg-icon icon-class="iconfont-shuipingzuo" class="constellation"></svg-icon>
      <span class="list-item-title">水平座</span>
    </div>
    <div class="list-item" draggable="true" style="--color: #f0e941">
      <svg-icon icon-class="iconfont-mojiezuo" class="constellation"></svg-icon>
      <span class="list-item-title">摩羯座</span>
    </div>
    <div class="list-item" draggable="true" style="--color: #da8218">
      <svg-icon icon-class="iconfont-chunvzuo" class="constellation"></svg-icon>
      <span class="list-item-title">处女座</span>
    </div>
    <div class="list-item" draggable="true" style="--color: #7ff0ec">
      <svg-icon icon-class="iconfont-shizizuo" class="constellation"></svg-icon>
      <span class="list-item-title">狮子座</span>
    </div>
  </div>
</template>

<script setup name="Draggable">
import { onMounted } from 'vue';

onMounted(() => {
  // 操作dom元素
  const list = document.querySelector('.list');
  const item = document.querySelectorAll('list-item');

  // 判断当前元素
  let source_node;
  // 开始拖动
  list.ondragstart = (e) => {
    source_node = e.target;
    recode(item);
    setTimeout(() => {
      e.target.classList.add('moving');
    }, 0);
    // 设置拖动效果
    e.dataTransfer.effectAllowed = 'move';
  };
  // 拖动在有效目标
  list.ondragover = (e) => {
    // 防止默认情况下允许删除
    e.preventDefault();
  };
  // 拖拽放入有效目标触发
  list.ondragenter = (e) => {
    e.preventDefault();
    if (e.target === list || e.target === source_node) {
      return false;
    }
    const childer = Array.from(list.children);
    const sourceIndex = childer.indexOf(source_node);
    const targetIndex = childer.indexOf(e.target);
    if (sourceIndex < targetIndex) {
      // 从下往上拖动
      list.insertBefore(source_node, e.target.nextElementSibling);
    } else {
      // 从上往下拖动
      if (!e.target == null || source_node == null) {
        return;
      }
      list.insertBefore(source_node, e.target);
    }
    last([e.target, source_node]);
  };
  // 拖放结束
  list.ondragend = (e) => {
    e.target.classList.remove('moving');
  };
});

// 重新计算位置
function recode(eleAll) {
  // getBoundingClientRect 返回元素对于视口信息
  for (let i = 0; i < eleAll; i++) {
    const { top, left } = eleAll[i].getBoundingClientRect();
    eleAll[i]._top = top;
    eleAll[i]._left = left;
  }
}
// 添加移动动画效果
function last(eleAll) {
  for (let i = 0; i < eleAll; i++) {
    const dom = eleAll[i];
    const { top, left } = dom.getBoundingClientRect();
    if (dom._left) {
      dom.style.transform = `translate3d(${dom._left - left}px,${
        dom._top - top
      }px,0px)`;
      // 重绘动画
      let rafId = requestAnimationFrame(function () {
        dom.style.transition = `transform 0.3s ease-out`;
        dom.style.transform = 'none';
      });
      dom.addEventListener('transitionend', () => {
        dom.style.transition = 'none';
        // 取消requestAnimationFrame调用请求
        cancelAnimationFrame(rafId);
      });
    }
  }
}
</script>

<style lang="scss" scoped>
body {
  background-color: #000;
}
.list {
  width: 300px;
  height: 360px;
  /* padding: 20px 0; */
  margin: 100px auto 0;
  display: flex;
  flex-direction: column;
  justify-content: space-around;
}
.list-item {
  width: 100%;
  display: flex;
  align-items: center;
  padding: 10px 16px;
  border-radius: 10px;
  /* margin-bottom: 20px; */
  background-color: var(--color);
}
.constellation {
  line-height: 2.5em;
  font-size: 20px;
  color: #fff;
}
.list-item-img {
  width: 30px;
  height: 30px;
}
.list-item-title {
  margin-left: 20px;
  color: #fff;
}
.list-item.moving {
  background-color: transparent;
  border: 2px dashed #ccc;
}
</style>
